/**
 * 
 */
package any.gwt.client.http;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;

/**
 * TODO: Doc me
 * 
 * @author keke <keke@codehaus.org>
 * @version
 * @revision $Revision:$
 */
public class AsynClient {
    public static interface PreSendProcessor {
        void process(RequestBuilder requestBuilder);
    }

    private class Callback implements RequestCallback {

        private final AsynClientListener listener;
        private final String             name;

        public Callback(final String name, final AsynClientListener listener) {
            this.name = name;
            this.listener = listener;
        }

        public void onError(final Request request, final Throwable exception) {
            fireEvent(new AsynClientEvent(AsynClient.this, name, true, request,
                    exception));

        }

        public void onResponseReceived(final Request request,
                final Response response) {
            fireEvent(new AsynClientEvent(AsynClient.this, name, request,
                    response));
        }

        protected void fireEvent(final AsynClientEvent event) {
            if (listener != null) {
                listener.fireEvent(event);
            } else if (listeners != null) {
                for (int i = 0; i < listeners.size(); i++) {
                    ((AsynClientListener) listeners.get(i)).fireEvent(event);
                }
            }
        }
    }

    static class RestRequestBuilder extends RequestBuilder {
        protected RestRequestBuilder(final String httpMethod, final String url) {
            super(httpMethod, url);
        }
    }

    private List listeners;

    public void addClientListener(final AsynClientListener listener) {
        if (listeners == null) {
            listeners = new ArrayList();
        }
        listeners.add(listener);
    }

    public void get(final String name, final String url, final String data) {
        get(name, url, data, null);
    }

    public void get(final String name, final String url, final String data,
            final AsynClientListener listener) {
        get(name, url, data, null, listener);
    }

    public void get(final String name, final String url, final String data,
            final PreSendProcessor processor, final AsynClientListener listener) {
        genericMethod(name, "GET", url, data, processor, listener);
    }

    public void post(final String name, final String url, final String data) {
        post(name, url, data, null);
    }

    public void post(final String name, final String url, final String data,
            final AsynClientListener listener) {
        post(name, url, data, null, listener);
    }

    public void post(final String name, final String url, final String data,
            final PreSendProcessor processor, final AsynClientListener listener) {
        genericMethod(name, "POST", url, data, processor, listener);
    }

    public void put(final String name, final String url, final String data) {
        put(name, url, data, null);
    }

    public void put(final String name, final String url, final String data,
            final AsynClientListener listener) {
        put(name, url, data, null, listener);
    }

    public void put(final String name, final String url, final String data,
            final PreSendProcessor processor, final AsynClientListener listener) {
        genericMethod(name, "PUT", url, data, processor, listener);
    }

    public void removeClientListener(final AsynClientListener listener) {
        if (listeners != null) {
            listeners.remove(listener);
        }

    }

    protected void genericMethod(final String name, final String method,
            final String url, final String data,
            final PreSendProcessor processor, final AsynClientListener listener) {
        final RestRequestBuilder builder = new RestRequestBuilder(method, url);
        if (processor != null) {
            processor.process(builder);
        }
        try {
            builder.sendRequest(data, new Callback(name, listener));
        } catch (final RequestException e) {
            throw new ClientException(e);
        }
    }

}
